/* nn_layer.h */
#ifndef __NN_LAYER_H__
#define __NN_LAYER_H__

#include <stdio.h>
#include <stdint.h>

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define NN_VECTOR_LENGTH_MAX   256u /* max operating length for each layer. */

/**
 * @beief 神经网络层结构体对象类型.
 */
typedef struct
{
    uint32_t n_input;  /*!< 输入向量长度. */
    uint32_t n_output; /*!< 输出向量长度, 也表示本层神经元数量. */
    float  * weight;   /*!< 权重矩阵, 列数=输入向量长度, 行数=输出向量长度. */
    float  * bias;     /*!< 偏置向量, 长度=输出向量长度. */
} nn_layer_t;

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/**
* @brief 初始化NN中必要的数据
*
*
*
* @return void
*/
void nn_init(void);


/**
* @brief 初始化人工神经网络层实例
*
* init函数只是填充层结构体, 但是在这里特别要注意一下各个参数的约束条件.
*
* @param[out] layer    指向一个待填充的层结构体实例对象
* @param[in]  n_input  本层输入的通道数
* @param[in]  n_output 本层输出的通道数, 也是本层内神经元的数量
* @param[in]  weight   指向一个权重数组(其实是矩阵), 矩阵的列数等于n_input, 矩阵的行数等于n_output
* @param[in]  bias     指向一个偏移量数组(向量), 向量的长度等于n_output
*
* @return void
*/
void nn_layer_init(nn_layer_t *layer, uint32_t n_input, uint32_t n_output, float *weight, float *bias);

/**
* @brief 执行一次层推导计算, 线性推导
*
* @param[in]  layer  指向一个已经配置好的层结构体实例对象
* @param[in]  input  本层的输入向量, 长度等于layer->n_input
* @param[out] output 本层的输出向量, 长度等于layer->n_output
*
* @return void
*/
void nn_layer_forward_linear_pq(nn_layer_t *layer, float *input, float *output);
void nn_layer_forward_linear_arm(nn_layer_t *layer, float *input, float *output);

/**
* @brief 激活函数, ReLU
*
* @param[in]  input  输入向量
* @param[out] output 输出向量
* @param[in]  len    向量长度
*
* @return void
*/
void nn_layer_activate_relu(float *input, float *output, uint32_t len);

/**
* @brief 激活函数, sigmoid
*
* @param[in]  input  输入向量
* @param[out] output 输出向量
* @param[in]  len    向量长度
*
* @return void
*/
void nn_layer_activate_sigmoid_pq(float *input, float *output, uint32_t len);
void nn_layer_activate_sigmoid_arm(float *input, float *output, uint32_t len);

/**
* @brief 激活函数, softmax
*
* @param[in]  input  输入向量
* @param[out] output 输出向量
* @param[in]  len    向量长度
*
* @return void
*/
void nn_layer_activate_softmax_pq(float *input, float *output, uint32_t len);
void nn_layer_activate_softmax_arm(float *input, float *output, uint32_t len);

/**
* @brief 激活函数, tanh
*
* @param[in]  input  输入向量
* @param[out] output 输出向量
* @param[in]  len    向量长度
*
* @return void
*/
void nn_layer_activate_tanh_pq(float *input, float *output, uint32_t len);
void nn_layer_activate_tanh_arm(float *input, float *output, uint32_t len);

/*******************************************************************************
 * Code
 ******************************************************************************/

#endif /* __NN_LAYER_H__ */

